using System;
using System.Collections.Generic;
using System.Net.WebSockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Mvvm.Services;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Mvvm.ViewModels
{
    public class XunFeiClient:IXunFeiClient
    {
        private const string x_appid = "a1df787d";
        private const string api_secret = "YTM5NmVlNmJkZDcxODU1NDhiYjZkZGY5";
        private const string api_key = "c1f6088a175c356645b2e4802690791a";
        private const string hostUrl = "wss://spark-api.xf-yun.com/v4.0/chat";
        private readonly CancellationTokenSource _cancellationTokenSource;
        
        public class JsonRequest
        {
            public Header header { get; set; }
            public Parameter parameter { get; set; }
            public Payload payload { get; set; }
        }

        public class Header
        {
            public string app_id { get; set; }
            public string uid { get; set; }
        }

        public class Parameter
        {
            public Chat chat { get; set; }
        }

        public class Chat
        {
            public string domain { get; set; }
            public double temperature { get; set; }
            public int max_tokens { get; set; }
        }

        public class Payload
        {
            public Message message { get; set; }
        }

        public class Message
        {
            public List<Content> text { get; set; }
        }

        public class Content
        {
            public string role { get; set; }
            public string content { get; set; }
        }
        
        public XunFeiClient()
        {
            _cancellationTokenSource = new CancellationTokenSource();
        }
//这里用于传入用户的输入
        public async Task<string> GetResponseAsync(string userInput)
        {
            
            string authUrl = GetAuthUrl();
            string url = authUrl.Replace("http://", "ws://").Replace("https://", "wss://");
            
            using (var webSocket0 = new ClientWebSocket())
            {
                try
                {
                    await webSocket0.ConnectAsync(new Uri(url), _cancellationTokenSource.Token);

                    var request = CreateRequest(userInput);
                    var jsonString = JsonConvert.SerializeObject(request);
                    var frameData = Encoding.UTF8.GetBytes(jsonString);

                    await webSocket0.SendAsync(new ArraySegment<byte>(frameData), WebSocketMessageType.Text, true, _cancellationTokenSource.Token);
                    Console.WriteLine("response");
                    var response = await ReceiveResponse(webSocket0, _cancellationTokenSource.Token);
                    Console.WriteLine(response);
                    return response;
                }
                catch (Exception e)
                {
                    throw new Exception($"Failed to get response from XunFei: {e.Message}", e);
                }
            }
        }

        private static string GetAuthUrl()
        {
            string date = DateTime.UtcNow.ToString("r");

            Uri uri = new Uri(hostUrl);
            StringBuilder builder = new StringBuilder("host: ").Append(uri.Host).Append("\n").Append("date: ").Append(date).Append("\n").Append("GET ").Append(uri.LocalPath).Append(" HTTP/1.1");

            string sha = HMACsha256(api_secret, builder.ToString());
            string authorization = string.Format("api_key=\"{0}\", algorithm=\"{1}\", headers=\"{2}\", signature=\"{3}\"", api_key, "hmac-sha256", "host date request-line", sha);

            string NewUrl = "https://" + uri.Host + uri.LocalPath;
            string path1 = "authorization" + "=" + Convert.ToBase64String(Encoding.UTF8.GetBytes(authorization));
            date = date.Replace(" ", "%20").Replace(":", "%3A").Replace(",", "%2C");
            string path2 = "date" + "=" + date;
            string path3 = "host" + "=" + uri.Host;

            NewUrl = NewUrl + "?" + path1 + "&" + path2 + "&" + path3;
            return NewUrl;
        }

        private static string HMACsha256(string apiSecretIsKey, string builder)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(apiSecretIsKey);
            using (HMACSHA256 hMACSHA256 = new HMACSHA256(bytes))
            {
                byte[] date = Encoding.UTF8.GetBytes(builder);
                byte[] hash = hMACSHA256.ComputeHash(date);
                return Convert.ToBase64String(hash);
            }
        }

        private static JsonRequest CreateRequest(string userInput)
        {
            return new JsonRequest
            {
                header = new Header { app_id = x_appid, uid = "12345" },
                parameter = new Parameter
                {
                    chat = new Chat
                    {
                        domain = "4.0Ultra",
                        temperature = 0.5,
                        max_tokens = 1280
                    }
                },
                payload = new Payload
                {
                    message = new Message
                    {
                        text = new List<Content>
                        {
                            //设定身份
                            new Content { role = "system", content =  " "
                            },
                            new Content { role = "user", content = userInput }
                        }
                    }
                }
            };
        }

        private async Task<string> ReceiveResponse(ClientWebSocket webSocket, CancellationToken token)
        {
            byte[] receiveBuffer = new byte[1024];
            WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), token);
            string response = "";
            while (!result.CloseStatus.HasValue)
            {
                if (result.MessageType == WebSocketMessageType.Text)
                {
                    string receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
                    JObject jsonObj = JObject.Parse(receivedMessage);
                    int code = (int)jsonObj["header"]["code"];

                    if (code == 0)
                    {
                        int status = (int)jsonObj["payload"]["choices"]["status"];
                        JArray textArray = (JArray)jsonObj["payload"]["choices"]["text"];
                        string content = (string)textArray[0]["content"];
                        response += content;

                        if (status != 2)
                        {
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        throw new Exception($"Request error: {receivedMessage}");
                    }
                }
                else if (result.MessageType == WebSocketMessageType.Close)
                {
                    throw new Exception("WebSocket connection was closed unexpectedly.");
                }

                result = await webSocket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), token);
            }

            return response;
        }
    }
}
